package com.thor.palmmall.util.billnumber;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.lang3.StringUtils;

import com.thor.commons.exception.ThorServiceException;
import com.thor.commons.util.Assert;

/**
 * 生成单据单号的工具。
 * 
 * @author Debenson
 * @since 0.1
 */
public class BillNumberTool {
  public static final int DEFAULT_BILL_NUMBER_LEN = 6;

  @PersistenceContext(unitName = "${thor-webui-core.persistent-unit}")
  protected EntityManager em;

  /**
   * 生成序列号。
   * 
   * @param name
   *          序列名称。
   * @return
   * @throws ThorServiceException
   */
  public int nextValue(String name) throws ThorServiceException {
    Assert.assertArgumentNotNull(name, "name");

    Query query = em.createNativeQuery("select _nextval(?) v");
    query.setParameter(1, name);
    @SuppressWarnings("unchecked")
    List<Object> results = query.getResultList();
    if (results.size() <= 0) {
      throw new ThorServiceException("生成序列号失败");
    }

    Integer value = (Integer) results.get(0);
    if (value == null) {
      throw new ThorServiceException("生成序列号失败");
    }
    return value;
  }

  /**
   * 生成单号。
   * 
   * @param billType
   *          单据类型，一般取实体短名称，禁止为null。
   * @return 唯一的新单号，但不保证连续性。
   * @throws ThorServiceException
   */
  public String nextBillNumber(String billType) throws ThorServiceException {
    return nextBillNumber(billType, "", DEFAULT_BILL_NUMBER_LEN);
  }

  // /**
  // * 生成单号。
  // *
  // * @param billType
  // * 单据类型，一般取实体短名称，禁止为null。
  // * @param flowNumLenth
  // * 流水号长度。-1表示不固定长度。
  // * @return 唯一的新单号，但不保证连续性。
  // * @throws ThorServiceException
  // */
  // public String nextBillNumber(String billType, int flowNumLenth) throws
  // ThorServiceException {
  // final TSDepart curOrg = ResourceUtil.getSessionUserDepart();
  // if (curOrg == null) {
  // throw new ThorServiceException("取不到当前组织，是不是没有登录？");
  // }
  // final String orgCode = curOrg.getOrgCode();
  // if (StringUtils.isBlank(orgCode)) {
  // throw new ThorServiceException("当前组织代码为空，请联系系统管理员");
  // }
  //
  // return nextBillNumber(billType, orgCode, flowNumLenth);
  // }

  /**
   * 生成单号。
   * 
   * @param billType
   *          单据类型，一般取实体短名称，禁止为null。
   * @param orgCode
   *          组织代码。
   * @return 唯一的新单号，但不保证连续性。
   * @throws ThorServiceException
   */
  public String nextBillNumber(String billType, String orgCode) throws ThorServiceException {
    return nextBillNumber(billType, orgCode, -1);
  }

  private static final SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");

  /**
   * 生成单号。 <br>
   * 生成规格： 5位组织代码 + 6位日期(yyMMdd) + flowNumLenth位流水号。 其中，流水号每日重复计算。 <br>
   * 示例: 00001 161206 00001
   * 
   * @param billType
   *          单据类型，一般取实体短名称，禁止为null。
   * @param orgCode
   *          当前组织代码，可空。
   * @param flowNumLenth
   *          流水号长度。-1表示不固定长度。
   * @return 唯一的新单号，但不保证连续性。
   * @throws ThorServiceException
   */
  public String nextBillNumber(String billType, String orgCode, int flowNumLenth)
      throws ThorServiceException {
    Assert.assertArgumentNotNull(billType, "billType");

    String suffix = StringUtils.trimToEmpty(orgCode);
    if (StringUtils.isNotBlank(suffix)) {
      suffix += "_";
    }
    final String dateStr = sdf.format(new Date());
    suffix += dateStr;

    // 取流水号
    final String key = billType + "_" + suffix;
    int value = nextValue(key);

    return String.format("%s%" + (flowNumLenth < 0 ? "" : "0" + flowNumLenth) + "d",
        orgCode + dateStr, value);
  }

}
